var SimpleTableInputMethod = InputMethod.extend({
	content_level: 0,
	content_total: 0,
	/* max_key_length: (integer)
           maximum length of preedit (If the preedit length reachs this value, onComplete is called)
        */
	max_key_length: 0,
	auto_complete: true,
        // internal used for selection choice list
	current_pos: 0,
	current_list: null,

	constructor: function(clv)
	{
		this.base();
		var key;
		var i;

		// convert the char map
		for(key in this.GetClass().char_map) {
			this.GetClass().char_map[key] = lib.utf16char(this.GetClass().char_map[key]);
		}
		clv = (!clv || clv > this.content_total) ? this.content_total : clv;
		this.content_level = 0;
		for(i=0;i<clv;i++) {
			this.DownloadComponentStatic(lib.sprintf('table%d',i));
		}
	},
	UpdateTable: function()
	{
		var i;
		var _this = this.GetClass();

		Debug.trace(1,"SimpleTableInputMethod: Update content level from %d...",this.content_level);
		for(this.content_level;;this.content_level++) {
			i = this.content_level;
			if(_this['table'+i]) {
				var key;
				var map = _this['table'+i];
				Debug.trace(1,"SimpleTableInputMethod: Content %d available...updating...",i);
				for(var key in map) {
					if(_this.table[key]) _this.table[key] = _this.table[key].concat(map[key]);
					else _this.table[key] = map[key];
				}
			}
			else break;
		}
		Debug.trace(1,"SimpleTableInputMethod: At Content level %d.",this.content_level);
	},
	onCompleteComponent: function(name)
	{
		var lv = parseInt(name.substr(5));
		var i;
		var _this = this.GetClass();

		Debug.trace(1,"SimpleTableInputMethod: Component %s download completed.",name);

		this.UpdateTable();
		if(this.ime.GetPreeditLength() > 0) {
			var key = this.ime.GetPreedit();
			this.current_list = this.GetClass().table[key];
			this.UpdateCandidate();
		}
	},
	onErrorComponent: function(name)
	{
		Debug.trace(0,"SimpleTableInputMethod: Component %s has errors.",name);
	},
	GetClass: function()
	{
		return SimpleTableInputMethod;
	},
	IMName: function()
	{
		return "SimpleTableInputMethod";
	},
	keydown_handler: function(obj,key) 
	{
		var b = true;
		switch(key) {
		case 8: // Backspace
			b = !this.onDeletePreedit(obj);
			break;
		case 188: // previous page
			b = !this.onPreviousPage(obj);
			break;
		case 190: // next page
			b = !this.onNextPage(obj);
			break;
		default:
			break;
		}
		return b;
	},
	keypress_handler: function(obj,key) 
	{
		var b = true;
		switch(key) {
		case 27: // Esc
			b = !this.onCancel(obj);
			break;
		case 32: // Space
			if(this.IsCandidateAvailable()) {
				this.onNextPage(obj);
				return false;
			}
			if(this.ime.GetPreeditLength() > 0) {
				this.onComplete(obj);
				return false;
			}
			break;
		case 49: case 50: case 51: case 52: case 53:
		case 54: case 55: case 56: case 57:
			if(this.IsCandidateAvailable()) b = !this.onSelectCandidate(obj,key-49);
			break;
		default:
			break;
		}

		if(!b) return false;

		if(this.ime.GetPreeditLength() >= this.max_key_length) return false;
		else {
			var ch = String.fromCharCode(key);
			var dch = this.GetClass().char_map[ch];

			if(dch) {
				if(this.current_list) this.onSelectCandidate(obj,0);
				this.ime.AppendPreedit(ch,dch);
				Debug.trace(1,"SimpleTableInputMethod: Append Preedit (%s,%s)",ch,dch);
			}
			else return true;
	
			if(this.ime.GetPreeditLength() == this.max_key_length && this.auto_complete) {
				Debug.trace(1,"SimpleTableInputMethod: Auto-complete!");
				this.onComplete(obj);
			}
			return false;
		}
	},
	onActive: function()
	{
		this.current_pos = 0;
		this.current_list = null;
	},
	onDeactive: function()
	{
		this.current_pos = 0;
		this.current_list = null;
	},
	onDeletePreedit: function(obj)
	{
		if(this.ime.GetPreeditLength() > 0) {
			this.ime.DeletePreedit(1,1);
			this.current_pos = 0;
			this.current_list = null;
			this.ime.ShowCandidateListWindow(false);
			return true;
		}
		else return false;
	},
	onCancel: function(obj)
	{
		this.ime.ResetPreedit();
		this.current_pos = 0;
		this.current_list = null;
	},
	IsCandidateAvailable: function()
	{
		if(this.current_list) return true;
		else return false;
	},
	onComplete: function(obj)
	{
		var key = this.ime.GetPreedit();
		var list = this.GetClass().table[key];
		var loaddone = (this.content_level == this.content_total) ? true : false;

		if(!list) {
			Debug.trace(1,"SimpleTableInputMethod: No lists for key=\"%s\".",key);
			this.ime.InvalidatePreedit();
			return false;
		}
		if(list.length == 0 && loaddone) {
			Debug.trace(1,"SimpleTableInputMethod: Zero records found for key=\"%s\".",key);
			this.ime.InvalidatePreedit();
			return false;
		}
		else if(list.length == 1 && loaddone) {
			Debug.trace(1,"SimpleTableInputMethod: One record found for key=\"%s\".",key);
			this.ime.SendString(obj,lib.utf16char(list[0]));
			this.ime.ResetPreedit();
			return true;
		}
		else {
			Debug.trace(1,"SimpleTableInputMethod: %d records found for key=\"%s\".",list.length,key);
			this.current_pos = 0;
			this.current_list = list;
			this.UpdateCandidate();
			return false;
		}
		return true;
	},
	UpdateCandidate: function()
	{
		if(this.current_list) {
			var i;

			for(i=0;i<9;i++) {
				var pos = this.current_pos + i;
				var loaddone = (this.content_level == this.content_total) ? true : false;

				if(pos >= this.current_list.length) this.ime.SetCandidate(i+1,loaddone ? ' ' : 'Still loading...');
				else this.ime.SetCandidate(i+1,lib.utf16char(this.current_list[pos]));
			}
			this.ime.ShowCandidateListWindow(true);
		}
		else {
			for(i=0;i<9;i++) {
				this.ime.SetCandidate(i+1,' ');
			}
			this.ime.ShowCandidateListWindow(false);
		}
	},
	SelectInternalCandidate: function(obj,pos)
	{
		this.ime.ResetPreedit();
		this.ime.SendString(obj,lib.utf16char(this.current_list[pos]));
		this.current_list = null;
		this.current_pos = 0;
		this.UpdateCandidate();
	},
	onSelectCandidate: function(obj,choice)
	{
		if(this.current_list) {
			var pos = this.current_pos + choice;
			if(pos < 0 || pos >= this.current_list.length) return false;
			this.SelectInternalCandidate(obj,pos);
			return true;
		}
		else return false;
	},
	onNextPage: function(obj)
	{
		if(this.current_list) {
			this.current_pos += 9;
			if(this.current_pos >= this.current_list.length) this.current_pos = 0;
			this.UpdateCandidate();
			return true;
		}
		else return false;
	},
	onPreviousPage: function(obj)
	{
		if(this.current_list) {
			this.current_pos -= 9;
			if(this.current_pos < 0) this.current_pos = this.current_list.length - this.current_list.length%9;
			this.UpdateCandidate();
			return true;
		}
		else return false;
	}
});
